package wikiPhilia_two;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Set;

import processing.core.PApplet;
import processing.core.PFont;
import processing.core.PVector;
import wpRelations.TsvTable;

public class WikiPhilia_two_003 {
	public HashMap<String, WNode> allNodes = new HashMap<String, WNode>();
	public ArrayList<WNode> allNodesList = new ArrayList<WNode>();
	public ArrayList<WNode> nodesLevelZeroList = new ArrayList<WNode>();
	public HashMap<String, WNode> nodesLevelZero = new HashMap<String, WNode>();
	public ArrayList<WNode> nodesLevelOneList = new ArrayList<WNode>();
	public HashMap<String, WNode> nodesLevelOne = new HashMap<String, WNode>();
	public ArrayList<WNode> nodesLevelTwoList = new ArrayList<WNode>();
	public HashMap<String, WNode> nodesLevelTwo = new HashMap<String, WNode>();
	public ArrayList<WEdge> allEdgesList = new ArrayList<WEdge>();
	PApplet p5;
	//TsvTableHuge inputTable;
	String personZeroTitle;
	//String inputFileName  = "Albert_Einstein_complete_stuff.tsv";
	String inputFileName;
	float minRadiusZero = 100f, maxRadiusZero = 200f,minRadiusOne = 200f, 
			maxRadiusOne = 400f;
	static float yAngle;
	static float xAngle;
	int loadSize = 10;
	float interval = 1f*30f; //in 30 fps
	int currentRow = 0;
	int maxLinkCount = -1;
	PFont myFont;
	float xOff, yOff, zOff;
	BigFile inputTable;
	Iterator<String> itr;
	
	WikiPhilia_two_003(PApplet parent, String name, String fileName ) {
		 personZeroTitle = name;
		 inputFileName = fileName;
		p5 = parent;
	}

	public void setup() {
		try {
			inputTable = new BigFile(inputFileName);
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		putNode(new WNode(p5, personZeroTitle), 0);
		nodesLevelZeroList.get(0).setType(WNode.TYPE_PERSON);
		nodesLevelZeroList.get(0).setPos(new PVector(0,0,0));
//		System.out.println("The table " + inputFileName + " has "
//				+ inputTable.getRowCount() + " rows.");
//		System.out.println("The table " + inputFileName + " has "
//				+ inputTable.getRowToStringArray(0).length + " coloumns.");
		p5.noFill();
		p5.noStroke();
		myFont = p5.loadFont("data\\TheSerifSemiBold-Plain-48.vlw");
		p5.textFont(myFont,16);
		p5.textAlign(p5.CENTER);
		p5.textMode(p5.MODEL);
         xOff = 0;
         yOff = 0;
         itr = inputTable.iterator();

	}

	public void draw() {
		p5.background(0);
        p5.translate(xOff,yOff,zOff);
		p5.translate(p5.width/2,p5.height/2);
		xAngle = p5.map(p5.mouseY,0,p5.height,0,p5.TWO_PI);
		yAngle = p5.map(p5.mouseX,0,p5.width,0,p5.TWO_PI)+p5.PI;
		p5.rotateX(xAngle);
		p5.rotateY(yAngle);

		//if (p5.frameCount % interval == 0) {
			addNodesEdges(loadSize);
			//currentRow = p5.min ((currentRow+loadSize),inputTable.getRowCount());
			setPositions(nodesLevelOneList, nodesLevelZeroList.get(0), minRadiusZero, maxRadiusZero, 300, 502);
			setPositions(nodesLevelTwoList, nodesLevelZeroList.get(0), minRadiusOne, maxRadiusOne, 300, 502);
			System.out.println("Nodes l0: " + nodesLevelZeroList.size());
			System.out.println("Nodes l1: " + nodesLevelOneList.size());
			System.out.println("Nodes l2: " + nodesLevelTwoList.size());
			System.out.println("Nodes alltogether: " + allNodesList.size());
			System.out.println("Edges alltogether: " + allEdgesList.size());
			System.out.println("Parsing line: " + currentRow + " (maybe) ");
			System.out.println("Max Link Count: " + maxLinkCount);
		//}
		for (int i = 0; i < allNodesList.size(); i++) {
			allNodesList.get(i).update();
			//allNodesList.get(i).display();
			
		}
		for (int i = 0; i < nodesLevelOneList.size(); i++) {
			nodesLevelOneList.get(i).display();
		}
		for (int i = 0; i < nodesLevelTwoList.size(); i++) {
			//nodesLevelTwoList.get(i).display();
		}
		for (int i = 0; i < allEdgesList.size(); i++) {
			//allEdgesList.get(i).display();
		}
	}

	public void setPositions(ArrayList<WNode> theNodes, WNode origin, float minR, float maxR, int hC, int vC) {
		int nodeCount = theNodes.size();
		float myInc = 1/(float)(nodeCount);
		//centerNode.setPos(new PVector(0,0,0));
		float hCycles = hC;
		float vCycles = vC;
		int originIndex;
		if (theNodes.contains(origin)) {
			originIndex= theNodes.indexOf(origin);
		} else {
			originIndex = -1;
		}
		for (int i = 0; i < nodeCount; i++) {
			if (i != originIndex) {
				float myRadius = minR - (theNodes.get(i).getLinksCount(3)/(float)maxLinkCount)*(maxR-minR);
				//float myRadius = maxR; ///just for testing purposes!
				float myIncH = myInc*i;
				float myIncV = myInc*i;
				float lambda = p5.TWO_PI*myInc*i*hCycles;
				float beta = p5.TWO_PI*myInc*i*vCycles;
				float x = origin.getcPos().x + p5.sin(lambda)*p5.cos(beta)*myRadius;
				float y = origin.getcPos().y + p5.sin(beta)*myRadius;
				float z = origin.getcPos().z + p5.cos(lambda)*p5.cos(beta)*myRadius;
				theNodes.get(i).setPos(new PVector(x,y,z));
			}
		}
		
	}

	
	public void addNodesEdges(int advance) {
		try {
			int i = 0;
			while (itr.hasNext() && i < advance) {
				String line = itr.next();
				System.out.println(line);
				String[] words = p5.split(line, "\t");
				String fromTitle = words[0];
				String toTitle = words[1];
				String fromType = words[2];
				String toType = words[3];
				int iFromType = WNode.TYPE_ARTICLE;
				int iToType = WNode.TYPE_ARTICLE;
				if (fromType.equalsIgnoreCase("person"))
					iFromType = WNode.TYPE_PERSON;
				if (fromType.equalsIgnoreCase("non_person"))
					iFromType = WNode.TYPE_NON_PERSON;
				if (fromType.equalsIgnoreCase("category"))
					iFromType = WNode.TYPE_CATEGORY;
				if (toType.equalsIgnoreCase("person"))
					iToType = WNode.TYPE_PERSON;
				if (toType.equalsIgnoreCase("non_person"))
					iToType = WNode.TYPE_NON_PERSON;
				if (toType.equalsIgnoreCase("category"))
					iToType = WNode.TYPE_CATEGORY;
				WNode fromNode = new WNode(p5, fromTitle, iFromType);
				WNode toNode = new WNode(p5, toTitle, iToType);
				//TODO: loops!!!!
				int myCaseFrom = 5;  
				int myCaseTo = 5;
				int myCase;///// is a product of the abovementioned
				if (nodesLevelZero.containsKey(fromTitle)) myCaseFrom = 1;
				if (nodesLevelOne.containsKey(fromTitle)) myCaseFrom = 2;
				if (nodesLevelTwo.containsKey(fromTitle)) myCaseFrom = 3;			 
				if (nodesLevelZero.containsKey(toTitle)) myCaseTo = 1;
				if (nodesLevelOne.containsKey(toTitle)) myCaseTo = 2;
				if (nodesLevelTwo.containsKey(toTitle)) myCaseTo = 3;
				myCase = myCaseFrom*myCaseTo;
				
				switch (myCase) {
				case 1: ///nonsense
					System.out.println("ERROR IN ALGORYTHM!");
					break;
				case 2: /// 0 <-> 1 check for loop?
					if (nodesLevelZero.containsKey(fromTitle)) {
						nodesLevelZero.get(fromTitle).incLinks(1);
						nodesLevelOne.get(toTitle).incBacklinks(0);	
						allEdgesList.add(new WEdge(p5,fromNode,toNode));
					} else {
						nodesLevelOne.get(fromTitle).incLinks(0);
						nodesLevelZero.get(toTitle).incBacklinks(1);	
						allEdgesList.add(new WEdge(p5,fromNode,toNode));
					}

					break;
				case 3: /// 0 <-> 3; nonsense
					System.out.println("ERROR IN ALGORYTHM!");
					break;
				case 4: /// 1 <-> 1: check for loop? 
					nodesLevelOne.get(fromTitle).incLinks(1);
					nodesLevelOne.get(toTitle).incBacklinks(1);
					allEdgesList.add(new WEdge(p5,fromNode,toNode));
					break;
				case 5: /// 0 <->NA => 0-1n
					if (nodesLevelZero.containsKey(fromTitle)) {
						putNode(toNode,1);
						nodesLevelZero.get(fromTitle).incLinks(1);
						toNode.incBacklinks(1);
						allEdgesList.add(new WEdge(p5,nodesLevelZero.get(fromTitle),toNode));
					} else {
						putNode(fromNode,1);
						nodesLevelZero.get(toTitle).incBacklinks(1);
						toNode.incLinks(1);
						allEdgesList.add(new WEdge(p5,fromNode,nodesLevelZero.get(toTitle)));
					}
					break;
				case 6: /// 1 <-> 2: check for loop?
					if (nodesLevelOne.containsKey(fromTitle)) {
						nodesLevelOne.get(fromTitle).incLinks(2);
						nodesLevelTwo.get(toTitle).incBacklinks(1);	
						allEdgesList.add(new WEdge(p5,fromNode,toNode));
					} else {
						nodesLevelTwo.get(fromTitle).incLinks(1);
						nodesLevelOne.get(toTitle).incBacklinks(2);	
						allEdgesList.add(new WEdge(p5,fromNode,toNode));
					}
					break;
				case 9: /// 2 <-> 2: check for loop?
					nodesLevelTwo.get(fromTitle).incLinks(2);
					nodesLevelTwo.get(toTitle).incBacklinks(2);
					allEdgesList.add(new WEdge(p5,fromNode,toNode));
					break;
				case 10: /// 1 <-> NA => 1-2n
					if (nodesLevelOne.containsKey(fromTitle)) {
						putNode(toNode,2);
						nodesLevelOne.get(fromTitle).incLinks(2);
						toNode.incBacklinks(1);
						allEdgesList.add(new WEdge(p5,nodesLevelOne.get(fromTitle),toNode));
					} else {
						putNode(fromNode,2);
						nodesLevelOne.get(toTitle).incBacklinks(2);
						toNode.incLinks(1);
						allEdgesList.add(new WEdge(p5,fromNode,nodesLevelOne.get(toTitle)));
					}
					break;
				case 15: /// 2 <-> NA => 2-2n
					if (nodesLevelTwo.containsKey(fromTitle)) {
						putNode(toNode,2);
						nodesLevelTwo.get(fromTitle).incLinks(2);
						toNode.incBacklinks(2);
						allEdgesList.add(new WEdge(p5,nodesLevelTwo.get(fromTitle),toNode));
					} else {
						putNode(fromNode,2);
						nodesLevelTwo.get(toTitle).incBacklinks(2);
						toNode.incLinks(2);
						allEdgesList.add(new WEdge(p5,fromNode,nodesLevelTwo.get(toTitle)));
					}
					break;
				case 25: /// NA <-> NA => 2n-2n
					putNode(fromNode,2);
					putNode(toNode,2);
					fromNode.incLinks(2);
					toNode.incBacklinks(2);
					allEdgesList.add(new WEdge(p5,fromNode,toNode));
					break;
					
				default:
					break;
				}
			}		
			i++;
			itr.wait(1000);
		} catch (Exception e) {
			// TODO: handle exception
		}
			

		//////LOOP handling!!!
		for (int i = 0; i < allNodesList.size(); i++) {
			if (maxLinkCount < allNodesList.get(i).getLinksCount(3)) maxLinkCount =allNodesList.get(i).getLinksCount(3);
		}

	}
	
	public void putNode(WNode theNode, int level) {
		switch (level) {
		case 0:
			nodesLevelZero.put(theNode.getTitle(), theNode);
			nodesLevelZeroList.add(theNode);
			allNodes.put(theNode.getTitle(), theNode);
			allNodesList.add(theNode);
			theNode.setLevel(WNode.LEVEL_ZERO);
			break;
		case 1:
			nodesLevelOne.put(theNode.getTitle(), theNode);
			nodesLevelOneList.add(theNode);
			allNodes.put(theNode.getTitle(), theNode);
			allNodesList.add(theNode);
			theNode.setLevel(WNode.LEVEL_ONE);
			break;
		case 2:
			nodesLevelTwo.put(theNode.getTitle(), theNode);
			nodesLevelTwoList.add(theNode);
			allNodes.put(theNode.getTitle(), theNode);
			allNodesList.add(theNode);
			theNode.setLevel(WNode.LEVEL_TWO);
			break;

		default:
			break;
		}
	}
}
